package com.hksj.wlw.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hksj.cbm.entity.DeviceInstance;
import com.hksj.cbm.entity.SpaceModel;
import com.hksj.cbm.entity.SpecialityModel;
import com.hksj.cbm.service.DeviceInstanceService;
import com.hksj.cbm.service.SpaceModelService;
import com.hksj.cbm.service.SpecialityModelService;
import com.hksj.cbm.vo.SpaceModelVO;
import com.hksj.common.core.common.Constants;
import com.hksj.common.core.common.SpecialityModelCodeEnum;
import com.hksj.common.core.util.DateUtil;
import com.hksj.wlw.dto.LeakWaterAlarmNumDTO;
import com.hksj.wlw.mapper.LeakWaterCockpitMapper;
import com.hksj.wlw.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author fjt
 * @data 2024/9/9 15:14
 * @describe 无线漏水-驾驶舱
 */
@Slf4j
@Service
public class LeakWaterCockpitService {

    @Autowired
    private LeakWaterCockpitMapper leakWaterCockpitMapper;
    @Autowired
    private DeviceInstanceService deviceInstanceService;
    @Autowired
    private SpecialityModelService specialityModelService;
    @Autowired
    private SpaceModelService spaceModelService;


    /**
     * 设备概览
     * @param dto
     * @return
     */
    public LeakWaterDeviceOverviewVo deviceOverView(LeakWaterAlarmNumDTO dto){
        dto.setCode(SpecialityModelCodeEnum.wireless_leak_water.getCode());
        List<DeviceInstance> deviceList = leakWaterCockpitMapper.queryDevice(dto);
        LeakWaterDeviceOverviewVo overviewVO = new LeakWaterDeviceOverviewVo();
        if (CollUtil.isEmpty(deviceList)){
            overviewVO.setOnlineRate(new BigDecimal(0.00));
            return overviewVO;
        }

        // 在线
        List<DeviceInstance> onLineDeviceList = deviceList.stream().
                filter(device -> "online".equals(device.getState()))
                .collect(Collectors.toList());
        // 离线
        List<DeviceInstance> offLineDeviceList = deviceList.stream().
                filter(device -> "offline".equals(device.getState()))
                .collect(Collectors.toList());

        // 未激活
        List<DeviceInstance> notActiveList = deviceList.stream().
                filter(device -> "notActive".equals(device.getState()))
                .collect(Collectors.toList());

        overviewVO.setTotal(deviceList.size());
        overviewVO.setOnlineNum(CollUtil.isNotEmpty(onLineDeviceList) ? onLineDeviceList.size() : 0);
        overviewVO.setOfflineNum(CollUtil.isNotEmpty(offLineDeviceList) ? offLineDeviceList.size() : 0);
        overviewVO.setNotActiveNum(CollUtil.isNotEmpty(notActiveList) ? notActiveList.size() : 0);
        // 占比
        if (CollUtil.isNotEmpty(onLineDeviceList)){
            BigDecimal onlineRate = new BigDecimal(onLineDeviceList.size()).divide(new BigDecimal(deviceList.size()),  5, BigDecimal.ROUND_HALF_UP);
            overviewVO.setOnlineRate(onlineRate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP));
        }
        return overviewVO;
    }


    /**
     * 按天统计7天内的报警数量
     * @return
     */
    public List<LeakWaterAlarmKindNumVo> queryAlarmNumByTime(LeakWaterAlarmNumDTO dto){
        // 7天前
        dto.setStartTime(DateUtil.convertToDate(DateUtil.convertToLocalDate(DateUtil.getNow()).minusDays(6)));
        dto.setEndTime(DateUtil.getYmdHms(DateUtil.getFormatDate(DateUtil.getNow(), DateUtil.DEFAULT_FORMAT_DATE) + " 23:59:59"));
        dto.setCode(SpecialityModelCodeEnum.wireless_leak_water.getCode());
        List<LeakWaterAlarmNumVo> list = leakWaterCockpitMapper.queryAlarmNumByTime(dto);
        Map<String, Integer> map = list.stream().collect(Collectors.toMap(p -> p.getCreateTime(), p -> p.getNum()));

        List<LocalDate> dateList = DateUtil.getDatesInRange(DateUtil.convertToLocalDate(dto.getStartTime()), DateUtil.convertToLocalDate(dto.getEndTime()));
        List<LeakWaterAlarmKindNumVo> voList = new ArrayList<>(dateList.size());
        dateList.forEach(date -> {
            String dateStr = date.format(DateTimeFormatter.ofPattern(DateUtil.DEFAULT_FORMAT_DATE));
            LeakWaterAlarmKindNumVo numVO = LeakWaterAlarmKindNumVo.builder().alarmTime(date).alarmNum(map.get(dateStr)).build();
            voList.add(numVO);
        });
        // 时间升序
        return voList.stream().sorted(Comparator.comparing(LeakWaterAlarmKindNumVo::getAlarmTime, Comparator.naturalOrder())).collect(Collectors.toList());
    }


    /**
     * 查询设备报警记录     当报警状态为空时查全部状态的报警记录(最近7天)
     * @param dto
     * @return
     */
    public List<LeakWaterAlarmVo> queryAlarmList(LeakWaterAlarmNumDTO dto){
        dto.setCode(SpecialityModelCodeEnum.wireless_leak_water.getCode());
        if (ObjectUtil.isNull(dto.getStatus())){
            // 查最近7天全部状态的报警记录
            dto.setStartTime(DateUtil.convertToDate(DateUtil.convertToLocalDate(DateUtil.getNow()).minusDays(6)));
            dto.setEndTime(DateUtil.getYmdHms(DateUtil.getFormatDate(DateUtil.getNow(), DateUtil.DEFAULT_FORMAT_DATE) + " 23:59:59"));
        }
        List<LeakWaterAlarmVo> list = leakWaterCockpitMapper.queryAlarmList(dto);
        // 设置每个设备的空间位置节点信息
        List<String> pathList = list.stream().map(LeakWaterAlarmVo::getPaths).distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(pathList)){
            return list;
        }

        // 查询设置的统计方式(按楼层/科室)
        LambdaQueryWrapper<SpecialityModel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SpecialityModel::getCode, SpecialityModelCodeEnum.wireless_leak_water.getCode());
        SpecialityModel specialityModel = specialityModelService.getOne(queryWrapper);
        if (ObjectUtil.isNull(specialityModel)){
            throw new RuntimeException("无线漏水监测系统缺少专业模型配置信息");
        }

        Map<String, List<SpaceModelVO>> pathNameMap = deviceInstanceService.devicePathConvertToUTF8(pathList);
        if (CollUtil.isEmpty(pathNameMap)){
            return list;
        }

        // 组装数据
        list.forEach(alarmVO -> {
            List<SpaceModelVO> spaceModelVOList = pathNameMap.get(alarmVO.getPaths());
            if (CollUtil.isNotEmpty(spaceModelVOList)){
                Map<String, String> map = spaceModelVOList.stream().collect(Collectors.toMap(p -> p.getSpaceItemValue(), p -> p.getModelName()));

                StringBuffer buffer = new StringBuffer();
                // 统计方式(1=按楼层统计 2=按科室统计)
                Integer statisticalMethod = specialityModel.getStatisticalMethod();
                if (Constants.ONE.equals(statisticalMethod)){
                    // 楼层
                    buffer.append(map.get(Constants.THREE_STR));
                }
                if (Constants.TWO.equals(statisticalMethod)){
                    // 科室
                    buffer.append(alarmVO.getDepartmentItemValueName());
                }

                // 房间
                if (StringUtils.isNotBlank(map.get(Constants.TWO_STR))){
                    buffer.append("-").append(map.get(Constants.TWO_STR));
                }
                alarmVO.setPathName(buffer.toString());
                // 点位
                String pointName = map.get(Constants.ONE_STR);
                alarmVO.setPointName(StringUtils.isNotBlank(pointName) ? pointName : null);
            }
        });
        return list;
    }


    /**
     * 当日、本周报警数量查询
     * @return
     */
    public LeakWaterTotalOfAlarmVo alarmNum(LeakWaterAlarmNumDTO dto){
        dto.setCode(SpecialityModelCodeEnum.wireless_leak_water.getCode());
        // 当日
        dto.setStartTime(DateUtil.getYmdHms(DateUtil.getYmd() + " 00:00:00"));
        dto.setEndTime(DateUtil.getYmdHms(DateUtil.getYmd() + " 23:59:59"));
        Integer currentDateNum = leakWaterCockpitMapper.total(dto);

        // 本周
        dto.setStartTime(DateUtil.getFirstDayOfWeek());
        Integer currentMonthNum = leakWaterCockpitMapper.total(dto);
        return LeakWaterTotalOfAlarmVo.builder().currentDateNum(currentDateNum).currentWeekNum(currentMonthNum).build();
    }



    /**
     * 报警数量排名(前5)
     * @param dto
     * @return
     */
    public List<LeakWaterAlarmNumTopFiveVo> alarmNumRanking(LeakWaterAlarmNumDTO dto){
        // 按设备分组统计报警次数
        dto.setCode(SpecialityModelCodeEnum.wireless_leak_water.getCode());
        List<LeakWaterAlarmNumRankingVo> rankingVoList = leakWaterCockpitMapper.alarmNumRankingGroupDevice(dto);
        if (CollUtil.isEmpty(rankingVoList)){
            return null;
        }

        // 查询设置的统计方式(按楼层/科室)
        LambdaQueryWrapper<SpecialityModel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SpecialityModel::getCode, SpecialityModelCodeEnum.wireless_leak_water.getCode());
        SpecialityModel specialityModel = specialityModelService.getOne(queryWrapper);
        if (ObjectUtil.isNull(specialityModel)){
            throw new RuntimeException("无线漏水监测系统缺少专业模型配置信息");
        }

        if (StringUtils.isNotBlank(dto.getPaths())){
            SpaceModel spaceModel = spaceModelService.querySpaceModelByPaths(dto.getPaths());
            Assert.notNull(spaceModel, "空间模型表中不存在此路径");
            // 是楼栋，则按科室或楼层排名
            if (Constants.FOUR_STR.equals(spaceModel.getSpaceItemValue())) {
                return groupByBuilding(rankingVoList, specialityModel);

            }else {
                // 非楼栋，则按单个设备排名  按报警次数降序排序
                rankingVoList = rankingVoList.stream()
                        .sorted(Comparator.comparing(LeakWaterAlarmNumRankingVo::getNum, Comparator.reverseOrder()))
                        .collect(Collectors.toList());
                // 取前5
                rankingVoList = rankingVoList.subList(0, Math.min(5, rankingVoList.size()));

                List<LeakWaterAlarmNumTopFiveVo> returnList = new ArrayList<>(5);
                rankingVoList.forEach(vo -> {
                    LeakWaterAlarmNumTopFiveVo fiveVo = LeakWaterAlarmNumTopFiveVo.builder()
                            .pathName(vo.getDeviceName()).num(vo.getNum()).build();
                    returnList.add(fiveVo);
                });
                return returnList;
            }
        }else {
            // 路径为空时默认按楼层或科室分组统计
            return groupByBuilding(rankingVoList, specialityModel);
        }
    }


    private List<LeakWaterAlarmNumTopFiveVo> groupByBuilding(List<LeakWaterAlarmNumRankingVo> rankingVoList, SpecialityModel specialityModel){
        // 统计方式(1=按楼层统计 2=按科室统计)
        Integer statisticalMethod = specialityModel.getStatisticalMethod();
        if (Constants.ONE.equals(statisticalMethod)){
            // 楼层
            Map<String, List<LeakWaterAlarmNumRankingVo>> rankingMap = rankingVoList.stream()
                    .collect(Collectors.groupingBy(r -> r.getFloorId() + "-" + r.getFloorName()));
            return convertTopFiveVo(rankingMap);
        }
        if (Constants.TWO.equals(statisticalMethod)){
            // 科室
            Map<String, List<LeakWaterAlarmNumRankingVo>> rankingMap = rankingVoList.stream()
                    .collect(Collectors.groupingBy(r -> r.getDepartmentItemValue() + "-" + r.getDepartmentItemValueName()));
            return convertTopFiveVo(rankingMap);
        }
        return null;
    }


    private List<LeakWaterAlarmNumTopFiveVo> convertTopFiveVo(Map<String, List<LeakWaterAlarmNumRankingVo>> rankingMap){
        if (CollUtil.isEmpty(rankingMap)){
            return null;
        }
        List<LeakWaterAlarmNumTopFiveVo> returnList = new ArrayList<>(rankingMap.size());

        for(Map.Entry<String, List<LeakWaterAlarmNumRankingVo>> entry : rankingMap.entrySet()){
            String pathName = entry.getKey().split("-")[1];
            Integer num = entry.getValue().stream().mapToInt(LeakWaterAlarmNumRankingVo::getNum).sum();
            LeakWaterAlarmNumTopFiveVo fiveVo = LeakWaterAlarmNumTopFiveVo.builder().pathName(pathName).num(num).build();
            returnList.add(fiveVo);
        }

        // 按报警次数降序排序
        returnList = returnList.stream()
                .sorted(Comparator.comparing(LeakWaterAlarmNumTopFiveVo::getNum, Comparator.reverseOrder()))
                .collect(Collectors.toList());
        // 取前5
        return returnList.subList(0, Math.min(5, returnList.size()));
    }


}
